package com.momo.service.sysSetting;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.momo.common.common.JSONResult;
import com.momo.common.error.RedisKeyEnum;
import com.momo.common.req.sysSetting.authority.BatchRoleUserReq;
import com.momo.common.req.sysSetting.authority.RoleReq;
import com.momo.common.req.sysmain.RedisUser;
import com.momo.common.res.authority.AclModuleLevelDto;
import com.momo.common.res.authority.LoginAuthReq;
import com.momo.common.util.DateUtil;
import com.momo.common.util.RedisUtil;
import com.momo.common.util.StrUtil;
import com.momo.mapper.dataobject.RoleAclDO;
import com.momo.mapper.dataobject.RoleDO;
import com.momo.mapper.dataobject.RoleUserDO;
import com.momo.mapper.dataobject.UserDO;
import com.momo.mapper.mapper.sysSetting.AuthorityMapper;
import com.momo.mapper.mapper.sysSetting.RoleMapper;
import com.momo.mapper.mapper.sysmain.SysUserMapper;
import com.momo.service.async.AclAsync;
import com.momo.service.authority.AdminAuthorityService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * Created by MOMO on 2019/3/22.
 */
@Service
@Slf4j
public class SysRoleServiceImpl implements SysRoleService {
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private AuthorityMapper authorityMapper;
    @Autowired
    private AdminAuthorityService authorityService;
    @Autowired
    private AclAsync aclAsync;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public JSONResult add(RoleReq roleReq, RedisUser redisUser) {
        int roleCount = roleMapper.checkRoleRepetition(roleReq.getSysRoleName(), roleReq.getGroupId(), null);
        if (roleCount > 0) {
            return JSONResult.errorMap("角色名称已存在");
        }
        RoleDO record = new RoleDO();
        BeanUtils.copyProperties(roleReq, record);
        //第三方的管理员只允许有一个
        if (!roleReq.getGroupId().equals(1L)) {
            if (checkAdminVipOne(record)) {
                return JSONResult.errorMap("管理员角色已存在");
            }
        }

        record.setCreateBy(redisUser.getSysUserName());
        record.setUpdateBy(redisUser.getSysUserName());
        record.setCreateTime(DateUtil.getDateTime());
        record.setUpdateTime(DateUtil.getDateTime());
        record.setSysRoleUuid(StrUtil.genUUID());
        roleMapper.insertSelective(record);
        aclAsync.roleToRedis(record);
        return JSONResult.ok("新增角色成功");
    }

    @Override
    public JSONResult modify(RoleReq roleReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(roleReq.getSysRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待编辑的角色不存在");
        }
        int roleCount = roleMapper.checkRoleRepetition(roleReq.getSysRoleName(), roleReq.getGroupId(), roleDO.getId());
        if (roleCount > 0) {
            return JSONResult.errorMap("角色名称已存在");
        }
        RoleDO aDo = new RoleDO();
        BeanUtils.copyProperties(roleReq, aDo);
        aDo.setId(roleDO.getId());
        //第三方的管理员只允许有一个
        if (!roleReq.getGroupId().equals(1L)) {
            if (checkAdminVipOne(aDo)) {
                return JSONResult.errorMap("管理员角色已存在");
            }
        }
        aDo.setUpdateBy(redisUser.getSysUserName());
        aDo.setUpdateTime(DateUtil.getDateTime());
        roleMapper.updateByPrimaryKeySelective(aDo);
        aclAsync.roleToRedis(aDo);
        return JSONResult.ok("更新角色成功");
    }

    @Override
    public JSONResult status(RoleReq roleReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(roleReq.getSysRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待编辑的角色不存在");
        }
        String statusMsg = "";
        //状态 0启用  1禁用
        if ("0".equals(roleReq.getSysRoleStatus())) {
            roleDO.setSysRoleStatus("1");
            statusMsg = "权限点状态 禁用 成功";
        } else if ("1".equals(roleReq.getSysRoleStatus())) {
            roleDO.setSysRoleStatus("0");
            statusMsg = "权限点状态 启用 成功";
        }
        roleDO.setUpdateBy(redisUser.getSysUserName());
        roleDO.setUpdateTime(DateUtil.getDateTime());
        roleMapper.updateByPrimaryKeySelective(roleDO);
        aclAsync.roleToRedis(roleDO);
        return JSONResult.ok(statusMsg);
    }

    @Override
    public JSONResult rolesToUser(BatchRoleUserReq batchRoleUserReq, RedisUser redisUser) {
        UserDO userDO = sysUserMapper.uuid(batchRoleUserReq.getUserUuid());
        if (null == userDO) {
            return JSONResult.errorMap("待授权的用户不存在");
        }
        List<Long> roles = batchRoleUserReq.getRoles();
        List<Long> originAclIdList = authorityMapper.rolesByUserId(userDO.getId());
        if (originAclIdList.size() == roles.size()) {
            Set<Long> originAclIdSet = Sets.newHashSet(originAclIdList);
            Set<Long> aclIdSet = Sets.newHashSet(roles);
            originAclIdSet.removeAll(aclIdSet);
            if (CollectionUtils.isEmpty(originAclIdSet)) {
                return JSONResult.ok("为用户授权角色成功");
            }
        }
        updateUserRoles(userDO.getId(), roles, redisUser, userDO.getGroupId());
        return JSONResult.ok("为用户授权角色成功");
    }

    @Override
    public JSONResult aclsToRole(BatchRoleUserReq batchRoleUserReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(batchRoleUserReq.getRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待授权的角色不存在");
        }
        List<RoleAclDO> roleAclDOS = batchRoleUserReq.getAcls();
        List<Long> acls = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(roleAclDOS)) {
            roleAclDOS.forEach(roleAclDO -> {
                acls.add(roleAclDO.getSysAclId());
            });
        }
        List<Long> originAclIdList = authorityMapper.aclsByRoleId(Arrays.asList(roleDO.getId()));
        if (originAclIdList.size() == acls.size()) {
            Set<Long> originAclIdSet = Sets.newHashSet(originAclIdList);
            Set<Long> aclIdSet = Sets.newHashSet(acls);
            originAclIdSet.removeAll(aclIdSet);
            if (CollectionUtils.isEmpty(originAclIdSet)) {
                return JSONResult.ok("为角色授权权限成功");
            }
        }
        updateRoleAcls(roleDO.getId(), roleAclDOS, redisUser, roleDO.getGroupId(), acls);
        return JSONResult.ok("为角色授权权限成功");
    }

    @Override
    public JSONResult roleHaveAclTree(LoginAuthReq loginAuthReq, RedisUser redisUser) {
        RoleDO roleDO = roleMapper.uuid(loginAuthReq.getRoleUuid());
        if (null == roleDO) {
            return JSONResult.errorMap("待授权的角色不存在");
        }
        loginAuthReq.setRoleId(roleDO.getId());
        List<AclModuleLevelDto> list = authorityService.roleTree(loginAuthReq, redisUser);
        return JSONResult.ok(list);
    }

    @Transactional
    public void updateRoleAcls(Long roleId, List<RoleAclDO> aclIdList, RedisUser redisUser, Long groupId, List<Long> acls) {
        roleMapper.deleteRoleAclsByRoleId(roleId);

        if (CollectionUtils.isEmpty(aclIdList)) {
            redisUtil.del(RedisKeyEnum.REDIS_ROLE_ACLS_MAP.getKey() + roleId);
            return;
        }
        List<RoleAclDO> roleUserList = Lists.newArrayList();
        for (RoleAclDO aclId : aclIdList) {
            RoleAclDO roleUserDO = new RoleAclDO();
            roleUserDO.setDelFlag("0");
            roleUserDO.setGroupId(groupId);
            roleUserDO.setSysAclId(aclId.getSysAclId());
            roleUserDO.setSysRoleId(roleId);
            roleUserDO.setSysAclPermissionType(aclId.getSysAclPermissionType());
            roleUserDO.setSysRoleAclUuid(StrUtil.genUUID());
            roleUserDO.setCreateBy(redisUser.getSysUserName());
            roleUserDO.setUpdateBy(redisUser.getSysUserName());
            roleUserDO.setUpdateTime(DateUtil.getDateTime());
            roleUserDO.setCreateTime(DateUtil.getDateTime());
            roleUserList.add(roleUserDO);
        }
        roleMapper.batchInsertRoleAcls(roleUserList);
        aclAsync.roleAclsToRedis(roleId, aclIdList);
    }

    @Transactional
    public void updateUserRoles(Long userId, List<Long> roleIdList, RedisUser redisUser, Long groupId) {
        roleMapper.deleteUserRolesByUserId(userId);

        if (CollectionUtils.isEmpty(roleIdList)) {
            redisUtil.del(RedisKeyEnum.REDIS_USER_ROLES_STR.getKey() + userId);
            return;
        }
        List<RoleUserDO> roleUserList = Lists.newArrayList();
        for (Long aclId : roleIdList) {
            RoleUserDO roleUserDO = new RoleUserDO();
            roleUserDO.setDelFlag("0");
            roleUserDO.setRoleId(aclId);
            roleUserDO.setGroupId(groupId);
            roleUserDO.setSysRoleUserUuid(StrUtil.genUUID());
            roleUserDO.setUserId(userId);
            roleUserDO.setCreateBy(redisUser.getSysUserName());
            roleUserDO.setUpdateBy(redisUser.getSysUserName());
            roleUserDO.setUpdateTime(DateUtil.getDateTime());
            roleUserDO.setCreateTime(DateUtil.getDateTime());
            roleUserList.add(roleUserDO);
        }
        roleMapper.batchInsertUserRoles(roleUserList);
        aclAsync.userRolesToRedis(userId, roleIdList);
    }

    //校验第三方管理员只允许有一个
    private boolean checkAdminVipOne(RoleDO roleDO) {
        return roleMapper.checkAdminVipOne(roleDO.getGroupId(), roleDO.getId()) > 1 ? true : false;
    }
}
